#ifndef QUEUE_WORKER_H_
#define QUEUE_WORKER_H_

#include <pthread.h>
#include "BlockingQueue.hh"
#include "Task.hh"

//
/**
 * \file Worker.hh
 * \author  jsk <jsk.jinsubkim@gmail.com>
 * \version 1.0
 *
 * \class Worker Worker.hh
 *
 * 사용자가 할당한 작업(Task)을 수행한다.
 * 
 * 워커는 하나의 스레드에서 실행되고, 작업을 관리하기 위한 방법으로 큐를 
 * 사용한다. 사용자가 태스크(Task 클래스)을 할당하면, 그 작업은 큐에 삽입된다.
 * 워커는 work 메소드를 호출하면 retire 메소드를 호출 하기 전까지 큐에 있는 
 * 작업을 하나씩 가져와 처리한다.
 */
class Worker
{
public:
	/**
	 * \name Worker
	 * \param TaskQueue 작업을 저장할 큐.
	 */
	Worker(BlockingQueue* Queue);
	
	/**
	 * \name work
	 * 
	 * 작업을 수행하기 시작한다.
	 * 
	 * 새로운 스레드를 생성한다. 생성된 스레드는 큐에 있는 작업을 가져와 하나씩
	 * 처리한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf work();
	
	/**
	 * \name setLife
	 * \param NumOfWorking 작업 횟수.
	 * 
	 * 지금부터 수행할 작업 횟수를 지정한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf setLife(USNumber NumOfWorking);
	
	/**
	 * \name fetchTask
	 * \param NewTask 할당된 작업.
	 * 
	 * 새로운 작업을 가져온다.
	 * 
	 * 큐에 작업을 삽입한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf fetchTask(Task* NewTask);
	
	/**
	 * \name retire
	 * 
	 * 작업 수행을 중단한다.
	 * 
	 * 새로운 작업을 받지 않고, 큐가 비워질 때까지 대기한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf retire();
	
// Worker
protected:
	/**
	 * \name doWorking
	 * 
	 * 작업을 수행한다.
	 * 
	 * 지정된 큐에서 작업을 하나씩 가져와 처리한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf doWorking();
	
	/**
	 * \name handleTask
	 * 
	 * 작업을 처리한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf handleTask(Task* AssignedTask);
	
	/**
	 * \name finalizeTask
	 * 
	 * 작업을 마무리 짓는다.
	 * 
	 * 큐에 작업이 없을 때 까지 기다린다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf finalizeTask();
	
	/**
	 * \name checkRetired
	 * 
	 * 계속 작업을 수행할 것 인지 종료할 것 인지 결정한다.
	 * 
	 * \return 
	 * 
	 * 작업을 수행할 수 있는 횟수(Life)가 0이 아니면 TRUE,
	 * 0이면 FALSEL.
	 */
	virtual bool checkRetired();
	
	/**
	 * \name updateLife
	 * 
	 * 수행할 수 있는 작업 횟수(Life)를 갱신한다.
	 * 
	 * Life가 0과 -1이 아니면, 작업 횟수(Life)를 감소시킨다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf updateLife();
	
// Thread
protected:
	/**
	 * \name createThread
	 * 
	 * 스레드를 생성한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf createThread();
	
	/**
	 * \name waitThread
	 * 
	 * 스레드의 함수가 종료되기를 기다린다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf waitThread();
	
	/**
	 * \name resign
	 * 
	 * 스레드가 retire 메소드에 의해서 종료되지 않은 경우를 처리한다.
	 * 
	 * 사용자가 retire 메소드를 호출하지 않을 수 있기 때문에 pthread_detach 
	 * 함수를 사용해서 스레드 종료와 함께 자원을 반환한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf resign();
	
	/**
	 * \name ThreadFunc
	 * \param This 해당 워커(IWorker)의 인스턴스.
	 * 
	 * 스레드의 시작 함수.
	 * 
	 * doWorking 메소드를 호출한다. 
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	static void* ThreadFunc(void* This);
	
	/**
	 * \name setAffinity
	 * 
	 * 프로세서 친화도(affinity)를 설정한다.
	 * 
	 * \return 
	 * 
	 * 성공할 경우 RETURN_OK, 
	 * 실패할 경우 RETURN_OK가 아닌 값.
	 */
	virtual ResultOf  setAffinity();
	
// Member
protected:
	/**
	 * 태스크 큐.
	 * 
	 * 큐가 thread safe하도록 설계되었기 때문에 워커(Worker 클래스)는 동기화에 
	 * 대해서 처리할 필요가 없다. 또 큐는 condition variable를 사용하기 때문에 
	 * 불필요한 경쟁을 피할 수 있다.
	 */
	BlockingQueue* QueueOfTask;
	
	/**
	 * 스레드가 생성되었는 나타낸다.
	 * 
	 * 기본 값은 FALSE이고, work 메소드에 이해서 TRUE로 변경된다.
	 * retire, resign 메소드에 의해서 FALSE로 변경된다.
	 */
	bool Working;
	
	/**
	 * 처리할 수 있는 작업 개수.
	 * 
	 * 기본 값은 -1이고, 작업을 수행할 때 마다 1씩 김소한다.
	 * Life가 -1일 경우에는 처리할 수 있는 작업의 개수에 제한이 없다는 것을 
	 * 의미한다.
	 */
	USNumber Life;
	
	/**
	 * 스레드 아이디.
	 */
	pthread_t TID;
	
	/**
	 * 인스턴스의 상태를 나타낸다.
	 * TRUE일 경우 정상, FALSE일 경우 비정상.
	 */
	bool State;
	
private:
	/**
	 * ???
	 */
	cpu_set_t ProcessorSet;
	
	/**
	 * ???
	 */
	static USNumber Count;
};

#endif //QUEUE_WORKER_H_